package main

import (
	"fmt"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

type Article struct {
	ArticleID uint    `gorm:"primaryKey;autoIncrement" json:"article_id"`
	Title     string  `json:"title"`
	Content   string  `json:"content"`
	Images    []Image `gorm:"foreignKey:ArticleID" json:"images"`
}

type Image struct {
	ImageID   uint   `gorm:"primaryKey;autoIncrement" json:"image_id"`
	ImageData string `json:"image_data"`
	ArticleID uint   `json:"article_id"`
}

var db *gorm.DB

func init() {
	var err error
	db, err = gorm.Open(sqlite.Open("articles.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	db.AutoMigrate(&Article{}, &Image{})
}
func main() {

	r := gin.Default()

	r.POST("/api/article", createArticle)
	r.PUT("/api/article", updateArticle)
	r.GET("/api/article/list", listArticles)
	r.GET("/api/article/id/:id", getArticleByID)

	// give arg: -p
	if len(os.Args) > 2 {
		if os.Args[1] == "-p" {
			r.Run(fmt.Sprint(":", os.Args[2]))
			return
		}
	}
	r.Run(":2344")

	// // 创建一个User
	// var user = models.User{
	// 	// Uid: ,
	// 	Name: "zinface",
	// 	Age:  18,
	// 	// CreatedAt: ,
	// }
	// if err := models.SaveUser(&user); err == nil {
	// 	fmt.Println("创建成功:", user.Name)
	// }

	// // 查询一个User
	// var find models.User
	// find, err := models.FindUserByName("zinface")
	// if err != nil {
	// 	panic(err)
	// }

	// fmt.Println("-------------------------")
	// fmt.Println("Uid:", find.Uid)
	// fmt.Println("Name:", find.Name)
	// fmt.Println("Age", find.Age)
	// fmt.Println("CreateAt", find.CreatedAt)
}

func createArticle(c *gin.Context) {
	var request struct {
		Title   string   `json:"title"`
		Content string   `json:"content"`
		Images  []string `json:"images"`
	}

	if err := c.ShouldBindJSON(&request); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	tx := db.Begin()
	article := Article{
		Title:   request.Title,
		Content: request.Content,
	}
	if err := tx.Create(&article).Error; err != nil {
		tx.Rollback()
		fmt.Printf("createArticle: %v\n", err.Error())
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create article"})
		return
	}

	for _, image_data := range request.Images {
		image := Image{
			ImageData: image_data,
			ArticleID: article.ArticleID,
		}

		if err := tx.Create(&image).Error; err != nil {
			tx.Rollback()
			fmt.Printf("err.Error(): %v\n", err.Error())
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create image"})
			return
		}

	}
	tx.Commit()
	c.JSON(http.StatusOK, gin.H{"message": "Article created successfully", "article_id": article.ArticleID})
}

func updateArticle(c *gin.Context) {
	var request struct {
		ArticleID uint     `json:"article_id"`
		Title     string   `json:"title"`
		Content   string   `json:"content"`
		Images    []string `json:"images"`
	}

	if err := c.ShouldBindJSON(&request); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
	}

	tx := db.Begin()

	var article Article
	if err := tx.First(&article, request.ArticleID).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusNotFound, gin.H{"error": "Article not found"})
		return
	}

	article.Title = request.Title
	article.Content = request.Content

	if err := tx.Save(&article).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update article"})
		return
	}

	if err := tx.Where("article_id = ?", request.ArticleID).Delete(&Image{}).Error; err != nil {
		tx.Rollback()
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete images"})
		return
	}

	for _, image_data := range request.Images {
		image := Image{
			ImageData: image_data,
			ArticleID: article.ArticleID,
		}

		if err := tx.Create(&image).Error; err != nil {
			tx.Rollback()
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create image"})
			return
		}
	}

	tx.Commit()
	c.JSON(http.StatusOK, gin.H{"message": "Article updated successfully"})
}
func listArticles(c *gin.Context) {
	var articles []Article
	if err := db.Preload("Images").Find(&articles).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch articles"})
		return
	}
	c.JSON(http.StatusOK, articles)
}
func getArticleByID(c *gin.Context) {
	id := c.Param("id")

	var article Article
	if err := db.Preload("Images").Find(&article, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Article not found"})
		return
	}
	c.JSON(http.StatusOK, article)
}
